package org.jsequences.reflect;

import com.google.common.base.Function;
import com.google.common.reflect.TypeToken;

/**
 * An abstract class which calls an instance method of a class with no parameters by reflection. Use
 * this class to create Method-References in a
 * concise way:
 * 
 * <pre class="code">
 * <code class="java">
 * public class Person {
 *   public String getName(){..}
 *   
 *   public static final Function&lt;Person,String&gt; GET_NAME = 
 *     new MethodFunction&lt;Person,String&gt;("getName"){};
 * }
 * </code>
 * </pre>
 * <p>
 * <b>Usage notes:</b> Instantiate this class <b>ONLY</b> in static final constants! Since the
 * initialization phase is unsafe thanks to reflection, refactorings might break the code.
 * Therefore, ensure that the Function is a constant and stays <b>as close to the method declaration
 * as possible</b>! After the static initialization is successful, the function is completely
 * typesafe and nearly as fast as implementing the anonymous function by hand. <i>As long as you
 * adhere to these guidelines, no refactoring should omit your reflective method and if it is, the
 * error is fail-fast and trivial to detect!</i>
 * <p>
 * <b>Implementation notes:</b> This class is abstract but without a single member to force all
 * users to instantiate it with an empty block {} as shown above. This is a technique called
 * "generic type capture", see {@link TypeToken}.
 * 
 * @param <I> the instance type
 * @param <R> the return type
 * @author Eric Giese
 */
public abstract class InstanceFunction<I, R> extends ReflectionMethod<I, R>
        implements Function<I, R> {

    /**
     * Instantiates this abstract type.
     * 
     * @param name the exact name of the method to call.
     */
    protected InstanceFunction(String name) {
        initInstanceMethod(name);
    }

    /**
     * Calls the MethodReference on the instance and returns the result.
     * 
     * @param input the object instance
     * @return the method result
     */
    public final R apply(I input) {
        return invoke(input);
    }

    /**
     * InstanceFunctions are equal only to other InstanceFunctions.
     */
    @Override
    protected final boolean canEqual(Object other) {
        return other instanceof InstanceFunction;
    }
}
